/**
 * Abstracts the DOM, CSS and JavaScript to form a manageable UI control.
 * 
 * TODO: implement default methods, events etc.
 * TODO: allow styling by applying themes ONLY.
 * 			 themes contain only values for properties that do not affect layout.
 * 			 a theme defines which values can be changed.
 * 			 a theme's property names do not coincide with CSS names.
 * 			 layout styles are part of the UIControl.
 * 			 layout variations should be implemented through subclassing.
 * 			 CSS can not be changed outside of a theme or a control!
 * TODO: create virtual namespaces for CSS styles, e.g. to seperate webpage styling from
 * 			 styling of generic UI controls that share the same document.
 * TODO: create CSS selectors in the same way queries are generated by the ORM classes
 * TODO: group CSS properties by type and get/set using accessors
 * TODO: drag-'n-drop and animation support through 'using'
 * 
 * @author Cref
 */

package hxtc.dom;

import hxtc.dom.style.Selector;
import hxtc.dom.states.Align;

using hxtc.dom.DOMTools;

class UIControl<TParent> extends Control {
	
	public var description:String;

	public var isVisible(default, null):Bool;

	private static var loadedStyles = new Hash();
	
	public function new(?d,tagName:String='div') {
		super(d, tagName);
		containerElement = element;
		isVisible = false;
		var tmp = element.className;
		element.className = getClassName();
		if (tmp != '') element.className += ' '+tmp;
	}
	
	public var forceToRight(default, setForceToRight):Bool;
	function setForceToRight(b:Bool) {
		setState(b?Align.right:Align.left);
		return b;
	}
	
	var containerElement(default,null):HTMLElement;
	
	public var parentControl(default,setParentControl):TParent;
	
	function setParentControl(parent:TParent):TParent {
		untyped parent.containerElement.appendChild(element);
		return this.parentControl=parent;
	}
	
	public function show() {
		if (isVisible) return;
		isVisible = true;
		dispatch(ControlEvent.SHOW);
	}
	
	//TODO: switch className
	//TODO: CSS3 transition to .hidden className and emulate for IE
	public function hide() {
		if (!isVisible) return;
		isVisible = false;
		dispatch(ControlEvent.HIDE);
	}
	
	public function toggle() isVisible?hide():show()
	
	/*
	 * safely switch between mutually exclusive states.
	 * namespace collisions are out of the question.
	 * TODO: move to Control
	 */
	function setState(state:Dynamic) {
		#if debug
		switch(Type.typeof(state)) {
			case TEnum(e)://continue
			default: throw new Error('state should be enumConstructor: '+state);
		}
		#end
		//TODO: cache names
		var enumName = Type.getEnumName(Type.getEnum(state)).split('.').join('-');
		var re = new RegExp('(?:^|\\s)(' + enumName + '\\S*)(?=\\s|$)', 'g');
		element.className = ES5.replace(element.className, re) + ' ' + enumName + '-' + Type.enumConstructor(state);
		return this;
	}
}